﻿using System;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using DTT.AreaOfEffectRegions;
using IQIGame.Onigao.Game;
using IQIGame.Onigao.Logic;
using LFloatMath.Math;
using UnityEngine;

namespace IQIGame.Onigao.GamePlay
{
    public class BattleMoveComponent : TComponent
    {
        private const float arriveSqrDistance = 0.001f;

        private UnitView unit;

        private float realSpeed;
        public float expectedSpeed;
        public Vector3 moveAspect;

        public EMoveType moveType { get; private set; }

        private Vector3 moveCenter;
        private float maxDistance = -LFloat.one;

        private List<Vector3> aiPath = new List<Vector3>();
        private Vector3 impactTargetPos; // 冲锋移动终点
        private Action onAIArrived;

        private float maxSpeed;
        private float normalSpeed => this.unit.unitType == EUnitType.Hero ? BattleConst.ViewMoveSpeed : BattleConst.ViewMonsterSpeed;

        public int aiMoveType;
        
        // 临时移动前记录的旧位置
        private Vector3 posBeforeTempMove;
        private Quaternion rotBeforeTempMove;

        // 这里的speed的长度在0~1之间
        public void SetSpeedAspect(Vector3 speed)
        {
            if (speed == Vector3.zero)
            {
                this.moveAspect = Vector2.zero;
                this.expectedSpeed = 0;
            }
            else
            {
                this.expectedSpeed = speed.magnitude * this.maxSpeed;
                this.moveAspect = speed.normalized;
            }
        }

        public override void OnUpdate(float deltaTime)
        {
            if (!Application.isPlaying)
            {
                return;
            }
            base.OnUpdate(deltaTime);

            var rViewComp = this.unit.GetComponent<UnitViewComponent>(ETComponentType.UnitViewComponent);
            // 移动时候表现层用碰撞处理
            switch (this.moveType)
            {
                case EMoveType.Input:
                {
                    var rFromPos = this.moveCenter;
                    this.realSpeed = Mathf.Lerp(this.realSpeed, this.expectedSpeed, 0.3f);
                    var rDeltaPos = this.realSpeed * deltaTime * this.moveAspect;
                    var rTargetPos = rViewComp.position + rDeltaPos;
                    var rDis = rTargetPos - rFromPos;
                    rDis = Vector3.ClampMagnitude(rDis, this.maxDistance);
                    rTargetPos = rFromPos + rDis;
                    rTargetPos = Vector3.ClampMagnitude(rTargetPos, BattleManager.Instance.ctrl.sceneCtrl.mapRadius);
                    rDeltaPos = rTargetPos - rViewComp.position;

                    // 转向
                    if (this.moveAspect != Vector3.zero)
                    {
                        rViewComp.transform.rotation = Quaternion.Lerp(rViewComp.rotation, Quaternion.LookRotation(this.moveAspect), 0.3f);
                    }
                    if (rDeltaPos != Vector3.zero)
                    {
                        rViewComp.characterCtrl.Move(rDeltaPos);
                        BattleManager.Instance.ctrl.sceneCtrl.CameraOnCharacterMove(rViewComp);

                        var rColComp = this.unit.GetComponent<CollisionViewComponent>(ETComponentType.CollisionViewComponent);
                        rColComp?.SetPos(rViewComp.position.ToLVector2XZ());
                    }
                    break;
                }
                case EMoveType.AI:
                {
                    if (this.aiPath.Count > 0)
                    {
                        var rTarget = this.aiPath[0];
                        var rCurPos = rViewComp.position;
                        var rCurToTarget = rTarget - rCurPos;
                        this.realSpeed = Mathf.Lerp(this.realSpeed, this.expectedSpeed, 0.3f);
                        var rDeltaPos = this.realSpeed * deltaTime * this.moveAspect;
                        if (rCurToTarget.x * rCurToTarget.x + rCurToTarget.z * rCurToTarget.z <= rDeltaPos.sqrMagnitude || Math.Abs(rCurToTarget.x) + Math.Abs(rCurToTarget.z) <= arriveSqrDistance) // 简单近似0
                        {
                            this.aiPath.RemoveAt(0);
                            rDeltaPos = rTarget - rCurPos;
                        }
                        else
                        {
                            rCurToTarget.y = 0;
                            this.SetSpeedAspect(rCurToTarget.normalized);

                            // 转向
                            rViewComp.transform.rotation = Quaternion.Lerp(rViewComp.rotation, Quaternion.LookRotation(this.moveAspect), 0.3f);
                        }
                        rViewComp.transform.Translate(rDeltaPos, Space.World); // AI移动忽略碰撞，避免造成卡死

                        var rColComp = this.unit.GetComponent<CollisionViewComponent>(ETComponentType.CollisionViewComponent);
                        rColComp?.SetPos(rViewComp.position.ToLVector2XZ());
                        BattleManager.Instance.ctrl.sceneCtrl.CameraOnCharacterMove(rViewComp);
                    }
                    else
                    {
                        this.moveType = EMoveType.None;
                        this.Stop();
                        this.onAIArrived?.Invoke();
                    }
                    break;
                }
                case EMoveType.Impact:
                {
                    bool bArrived = false;
                    var rCurPos = rViewComp.position;
                    var rTarget = this.impactTargetPos;
                    var rCurToTarget = rTarget - rCurPos;
                    this.realSpeed = Mathf.Lerp(this.realSpeed, this.expectedSpeed, 0.3f);
                    var rDeltaPos = this.realSpeed * deltaTime * this.moveAspect;
                    var rNextPos = rCurPos + rDeltaPos;
                    // 只计算XZ
                    if (rCurToTarget.x * rCurToTarget.x + rCurToTarget.z * rCurToTarget.z <= rDeltaPos.sqrMagnitude ||
                        (rNextPos - rTarget).sqrMagnitude <= arriveSqrDistance)
                    {
                        rDeltaPos = rTarget - rCurPos;
                        bArrived = true;
                    }
                    rViewComp.transform.Translate(rDeltaPos, Space.World); // 移动忽略碰撞，避免造成卡死

                    var rColComp = this.unit.GetComponent<CollisionViewComponent>(ETComponentType.CollisionViewComponent);
                    rColComp?.SetPos(rViewComp.position.ToLVector2XZ());
                    BattleManager.Instance.ctrl.sceneCtrl.CameraOnCharacterMove(rViewComp);
                    if (bArrived)
                    {
                        this.Stop();
                    }
                    break;
                }
            }

            var rAnimComp = this.unit.GetComponent<BattleAnimationComponent>(ETComponentType.BattleAnimationComponent);
            rAnimComp.SetAnimeSpeed(this.realSpeed / this.normalSpeed); // 常规满速为1
        }

        private BattleSceneEntityView mMoveRangeEffect;

        public async UniTask SetInputMove(Vector3 center)
        {
            this.moveCenter = center;
            var rAttr = this.unit.GetComponent<AttributeViewComponent>(ETComponentType.AttributeViewComponent);
            this.maxDistance = (rAttr.Get(EAttributeType.MoveRange) / LFloat.thousand).ToFloat();
            this.maxSpeed = this.normalSpeed;
            this.moveType = EMoveType.Input;

            this.mMoveRangeEffect = ManagerCenter.Entity.Get(PathConstant.GetBattleCommonPrefabPath("MoveRange"),
                (int)EntityPoolGroupType.BattleSceneEntity) as BattleSceneEntityView;
            await this.mMoveRangeEffect.Load();
            this.mMoveRangeEffect.transform.position = this.moveCenter;
            var rRegion = this.mMoveRangeEffect.gameObject.GetComponent<CircleRegion>();
            rRegion.Radius = this.maxDistance;
        }

        public void OutInput()
        {
            if (this.mMoveRangeEffect != null)
            {
                this.mMoveRangeEffect.Put();
                this.mMoveRangeEffect = null;
            }
            this.Stop();
        }

        public async UniTask AIMove(List<UpdateVector2> path, Action onArrived = null)
        {
            this.maxDistance = -LFloat.one;
            this.aiPath.Clear();
            for (int i = 0; i < path.Count; i++)
            {
                this.aiPath.Add(path[i].ToLVector().ToVector3XZ());
            }
            // 特殊移动方式这里加启动
            if (this.aiMoveType != 0 && this.aiPath.Count > 0)
            {
                var rMoveConfig = TableCenter.battleAIMove.Get(this.aiMoveType);
                switch (rMoveConfig.Type)
                {
                    // 默认
                    case 0:
                        this.maxSpeed = this.normalSpeed;
                        break;
                    // 冲锋
                    case 1:
                    {
                        this.maxSpeed = rMoveConfig.Param[1] / 1000f; // 毫米转米
                        var rFirstForward = path[0].ToLVector() - this.unit.pos;
                        this.unit.forward = rFirstForward; // 临时指定方向来转向
                        var rViewComp = this.unit.GetComponent<UnitViewComponent>(ETComponentType.UnitViewComponent);
                        await rViewComp.SyncPos();
                        var rAnimationComp = this.unit.GetComponent<BattleAnimationComponent>(ETComponentType.BattleAnimationComponent);
                        rAnimationComp.SetRush(true);
                        // 冲锋前置蓄力动作持续时间
                        await UniTask.Delay(rMoveConfig.Param[0]);
                        break;
                    }
                }
            }
            else
            {
                this.maxSpeed = this.normalSpeed;
            }

            this.onAIArrived = onArrived;
            this.moveType = EMoveType.AI;

            while (this.moveType == EMoveType.AI)
            {
                await UniTask.Yield();
            }
        }

        /// <summary>
        ///  冲撞的动作由timeline控制，这里只有位移
        /// </summary>
        /// <param name = "targetPos"></param>
        /// <param name = "speed"></param>
        /// <param name = "aspect"></param>
        public async UniTask Impact(LVector2 targetPos, LFloat speed, LVector2 aspect)
        {
            this.unit.forward = aspect;
            this.maxSpeed = speed.ToFloat();
            this.moveType = EMoveType.Impact;
            this.impactTargetPos = targetPos.ToVector3XZ();
            this.SetSpeedAspect(aspect.ToVector3XZ().normalized);

            while (this.moveType == EMoveType.Impact)
            {
                await UniTask.Yield();
            }
        }

        public void TempMove()
        {
            this.moveType = EMoveType.TempMove;
            var rUnitViewComp = this.unit.GetComponent<UnitViewComponent>(ETComponentType.UnitViewComponent);
            this.posBeforeTempMove = rUnitViewComp.position;
            this.rotBeforeTempMove = rUnitViewComp.rotation;
        }

        public void Stop()
        {
            var rViewComp = this.unit.GetComponent<UnitViewComponent>(ETComponentType.UnitViewComponent);
            if (this.moveType == EMoveType.TempMove)
            {
                rViewComp.transform.localPosition = this.posBeforeTempMove;
                rViewComp.transform.localRotation = this.rotBeforeTempMove;
                this.posBeforeTempMove = Vector3.zero;
                this.rotBeforeTempMove = Quaternion.identity;
            }
            this.moveType = EMoveType.None;
            this.moveAspect = Vector3.zero;
            this.realSpeed = 0;
            this.expectedSpeed = 0;
        }

        protected override void OnDispose()
        {
            if (this.mMoveRangeEffect != null)
            {
                this.mMoveRangeEffect.Put();
                this.mMoveRangeEffect = null;
            }
        }

        public override void OnCreate(TEntity entity)
        {
            this.unit = entity as UnitView;
        }
    }

    public enum EMoveType
    {
        None,
        Input,
        AI,
        Impact,
        TempMove,
    }
}